package main;

import handlers.ClientHandler;

import java.net.ServerSocket;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.List;

/**
 * This class describes the server-side application. This is all console/text based and is responsible
 * for displaying information about connections to any viewer. It's actual function is to act
 * as a middle-point for clients wishing to access the same information simultaneously and will
 * perform modifications to information received from client's. 
 * 
 * Upon a successful update, all connected client's (and future connections) will be able to instantly
 * view any updates by all other client's. Works on a "cloud computing" model.
 * 
 * 
 * @author Oliver Behncke 
 * @author Holly Denton 
 * @author Matthew McCarthy
 * @author John Quinlivan
 *
 */
public class ServerMain extends Thread {

	/* Default socket for all incoming connections */
	private ServerSocket socket;

	/* Allows interaction between clients */
	private List<ClientHandler> connectedClients;

	/**
	 * Instantiates the server
	 */
	public ServerMain() {

		/* Print the date to the terminal */
		System.out.println("Hello user! Time is: " + new Date());

		System.out.println("\nWelcome to the KPS server - this server controls all the information database.");
		System.out.println("\nStarting server...");

		/* A storage of all the valid connections */
		connectedClients = new ArrayList<ClientHandler>();

		/* Attempt to create a server socket */
		try {
			socket = new ServerSocket(20000);
		} catch (Exception e) {
			System.err.println("\nError thrown in attempting to establish a server socket on port 20000! Exiting!");
			System.exit(-1);
		}
	}

	@Override
	public void run(){

		/* Inform the front-end user of successful instantiation */
		System.out.println("\nServer successfully started on port 20000!");
		System.out.println("Server will run indefinitely until manually closed.");

		/* Runs indefinitely until closed */
		while(true){
			try {
				ClientHandler temp = new ClientHandler(socket.accept(), this);
				connectedClients.add(temp);
				temp.start();
			} catch (Exception e) {
				System.out.println(
						"\nError thrown! Client \"" + socket.getInetAddress() + 
						"\" has failed to accept a connection on local port " 
						+ socket.getLocalPort() + "! Aborting!");
			}
		}
	}

	/**
	 * Informs all clients of the changes to the database
	 */
	public void updateAllClients(){
     try{
             for(ClientHandler c :Collections.synchronizedList(connectedClients)){
               /* Won't take no for an answer */
               while(!c.sendFile("data/database.xml")){}
             } 
          } catch(Exception e){}
	}

	/**
	 * Removes a client from the list of all connected clients
	 * @param removeMe
	 */
	public void removeClientFromValidClients(ClientHandler removeMe){
          try{
            Collections.synchronizedList(connectedClients).remove(removeMe);
          } catch(Exception e) {}
	}


	/**
	 * Begins an instance of a server - the object is multi-threaded but
	 * takes no arguments at run-time. All output is text-based and the 
	 * server is intended to be as "hands-off" as possible.
	 * 
	 * @param args An array of strings that may be passed at run-time
	 */
	public static void main(String[] args){
		new ServerMain().start();
	}


}
